/**
 * 
 */
package org.h2.table;

import java.sql.SQLException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;

import org.h2.engine.Session;
import org.h2.index.ExternIndex;
import org.h2.index.Index;
import org.h2.index.IndexType;
import org.h2.message.Message;
import org.h2.result.Row;
import org.h2.schema.Schema;
import org.h2.util.ObjectArray;
import org.h2.util.StringUtils;

/**
 * @author falario
 *
 */
public class TableExtern extends Table {
	
	private ObjectArray indexes=new ObjectArray();
	private String pkColumnNames[];
	private TableExternAdapter delegated = null;
	
	private static HashMap typesMap;
	
	static{
		typesMap=new HashMap();
	}
	
    public static boolean registerType(String typeName, Class clase){
    	
    	if(typesMap.put(typeName.toLowerCase(), clase)==null)
    		return true;
    	else
    		return false;
    }
    
    public static Class getClass(String typeName){
    	return (Class)typesMap.get(typeName.toLowerCase());
    }

	/**
	 * @param schema
	 * @param id
	 * @param name
	 * @param persistent
	 */
	public TableExtern(Schema schema, int id, String name, Column[] columns, String pkColumnNames[], boolean persistent, String type, Hashtable parameters) throws SQLException{
		super(schema, id, name, persistent);
		// TODO Auto-generated constructor stub
		try{
	        try{
	        	if(type==null){
	        		throw new SQLException("Parameter \""+TableExternAdapter.S_TYPE+"\" not found");
	        	}
	        	Class adapterClass=getClass(type);
	        	if(adapterClass==null){
	        		throw new SQLException("Table type is not valid");
	        	}
	        	this.delegated = (TableExternAdapter)adapterClass.newInstance();
	        	this.delegated.initialize(this, parameters, columns);
	        }
	        catch(IllegalAccessException except){
	        	 throw Message.convert(except);
	        }
	        catch(NullPointerException except){
	        	throw Message.convert(except);
	        }
	        catch(Exception except){
	        	throw Message.convert(except);
	        }
	        
	        if(columns==null || columns.length==0) this.setColumns(this.delegated.getColumns());
	        else this.setColumns(columns);
			
	        //scanIndex = new ScanIndex(this, id, cols, IndexType.createScan(persistent));
	        Index index=new ExternIndex(this, this.delegated, id, null, this.getColumns(), IndexType.createScan(true));
			//Index index = new ExternIndex(this, this.delegated, id, null, array, IndexType.createNonUnique(false));
	        indexes.add(index);
	        
	        this.pkColumnNames=pkColumnNames;
	        if(this.pkColumnNames!=null){
		        ObjectArray pks=new ObjectArray();
		        for(int i=0;i<pkColumnNames.length;i++){
		        	pks.add(this.getColumn(pkColumnNames[i]));
		        }
		        addIndex(pks, IndexType.createPrimaryKey(true, false));
	        }
		}
		catch(SQLException except){
			throw except;
		}
	}
	
	public TableExternAdapter getDelegated(){
		return this.delegated;
	}
	
    private void addIndex(ObjectArray list, IndexType indexType) {
        Column[] cols = new Column[list.size()];
        list.toArray(cols);
        Index index = new ExternIndex(this, this.delegated, 0, null, cols, indexType);
        indexes.add(index);
    }

	/* (non-Javadoc)
	 * @see org.h2.table.Table#lock(org.h2.engine.Session, boolean)
	 */
	public void lock(Session session, boolean exclusive) throws SQLException {
		// TODO Auto-generated method stub
		//nothing to do
	}

	/* (non-Javadoc)
	 * @see org.h2.table.Table#close(org.h2.engine.Session)
	 */
	public void close(Session session) throws SQLException {
		// TODO Auto-generated method stub
		this.delegated.closeSource();
	}

	/* (non-Javadoc)
	 * @see org.h2.table.Table#unlock(org.h2.engine.Session)
	 */
	public void unlock(Session s) {
		// TODO Auto-generated method stub
		//nothing to do
	}

	/* (non-Javadoc)
	 * @see org.h2.table.Table#addIndex(org.h2.engine.Session, java.lang.String, int, org.h2.table.Column[], org.h2.index.IndexType, int, java.lang.String)
	 */
	public Index addIndex(Session session, String indexName, int indexId,
			Column[] cols, IndexType indexType, int headPos, String comment)
			throws SQLException {
		// TODO Auto-generated method stub
		throw Message.getUnsupportedException();
	}

	/* (non-Javadoc)
	 * @see org.h2.table.Table#removeRow(org.h2.engine.Session, org.h2.result.Row)
	 */
	public void removeRow(Session session, Row row) throws SQLException {
		// TODO Auto-generated method stub
		this.delegated.removeData(session, row);
	}

	/* (non-Javadoc)
	 * @see org.h2.table.Table#truncate(org.h2.engine.Session)
	 */
	public void truncate(Session session) throws SQLException {
		// TODO Auto-generated method stub
		throw Message.getUnsupportedException();
	}

	/* (non-Javadoc)
	 * @see org.h2.table.Table#addRow(org.h2.engine.Session, org.h2.result.Row)
	 */
	public void addRow(Session session, Row row) throws SQLException {
		// TODO Auto-generated method stub
		this.delegated.insertData(session, row);
	}

	/* (non-Javadoc)
	 * @see org.h2.table.Table#checkSupportAlter()
	 */
	public void checkSupportAlter() throws SQLException {
		// TODO Auto-generated method stub
		throw Message.getUnsupportedException();
	}

	/* (non-Javadoc)
	 * @see org.h2.table.Table#getTableType()
	 */
	public String getTableType() {
		// TODO Auto-generated method stub
		return Table.TABLE_EXTERN;
	}

	/* (non-Javadoc)
	 * @see org.h2.table.Table#getScanIndex(org.h2.engine.Session)
	 */
	public Index getScanIndex(Session session) throws SQLException {
		// TODO Auto-generated method stub
		return (Index) indexes.get(0);
	}

	/* (non-Javadoc)
	 * @see org.h2.table.Table#getUniqueIndex()
	 */
	public Index getUniqueIndex() {
		// TODO Auto-generated method stub
        for(int i=0; i<indexes.size(); i++) {
            Index idx = (Index) indexes.get(i);
            if(idx.getIndexType().isUnique()) {
                return idx;
            }
        }
        return null;
	}

	/* (non-Javadoc)
	 * @see org.h2.table.Table#getIndexes()
	 */
	public ObjectArray getIndexes() {
		// TODO Auto-generated method stub
		return indexes;
	}

	/* (non-Javadoc)
	 * @see org.h2.table.Table#isLockedExclusively()
	 */
	public boolean isLockedExclusively() {
		// TODO Auto-generated method stub
		return false;
	}

	/* (non-Javadoc)
	 * @see org.h2.table.Table#getMaxDataModificationId()
	 */
	public long getMaxDataModificationId() {
		// TODO Auto-generated method stub
		return Long.MAX_VALUE;
	}

	/* (non-Javadoc)
	 * @see org.h2.table.Table#canGetRowCount()
	 */
	public boolean canGetRowCount() {
		// TODO Auto-generated method stub
		return this.delegated.canGetRowCount();
	}

	/* (non-Javadoc)
	 * @see org.h2.table.Table#canDrop()
	 */
	public boolean canDrop() {
		// TODO Auto-generated method stub
		return true;
	}

	/* (non-Javadoc)
	 * @see org.h2.table.Table#getRowCount()
	 */
	public int getRowCount() throws SQLException {
		// TODO Auto-generated method stub
		return this.delegated.getRowCount();
	}

	public String getDropSQL() {
		// TODO Auto-generated method stub
		return "DROP TABLE IF EXISTS " + getSQL();
	}

	/* (non-Javadoc)
	 * @see org.h2.engine.DbObject#getCreateSQL()
	 */
	public String getCreateSQL() {
		// TODO Auto-generated method stub
        StringBuffer buff = new StringBuffer();
        buff.append("CREATE EXTERN TABLE ");
        buff.append(getSQL());
        if(comment != null) {
            buff.append(" COMMENT ");
            buff.append(StringUtils.quoteStringSQL(comment));
        }
        
        boolean saveColumns=false;
        try{
        	saveColumns=Boolean.valueOf(this.delegated.getParam(this.delegated.S_STORED_COLUMNS)).booleanValue();
        }
        catch(SQLException except){
        	
        }
        catch(Exception except){
        	
        }
        
        if(saveColumns){
	        buff.append("(\n");
	        for (int i = 0; i < columns.length; i++) {
	            Column column = columns[i];
	            if (i > 0) {
	                buff.append(",\n    ");
	            }
	            buff.append(column.getCreateSQL());
	        }
	        buff.append("\n)");
        }
        buff.append("\n");
        buff.append("SOURCE (");
        buff.append("type");
        buff.append(" = ");
        buff.append("\""+this.delegated.getTypeName()+"\"");
        Hashtable parametros=this.delegated.getParams();
        Enumeration keys=parametros.keys();
        if(keys.hasMoreElements()) buff.append(", ");
        Object key=null;
        Object value=null;
        while(keys.hasMoreElements()){
        	key=keys.nextElement();
        	value=parametros.get(key);
        	if(value!=null && !String.valueOf(value).equalsIgnoreCase("null")){
        		buff.append((String.valueOf(key)));
        		buff.append(" = ");
        		buff.append(String.valueOf("\""+value+"\""));
        		if(keys.hasMoreElements()){
        			buff.append(", ");
        		}
        	}
        }        
        buff.append(")");
        String s=buff.toString();
        return s;
        //return buff.toString();
	}

	/* (non-Javadoc)
	 * @see org.h2.engine.DbObject#checkRename()
	 */
	public void checkRename() throws SQLException {
		// TODO Auto-generated method stub
		//nothing to do
	}
}